﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Protocol;
using MQTTnet.Server;
using Splat;
using static System.Windows.Forms.Design.AxImporter;
namespace WpfMqttAnalyzeApp.Services
{
    public delegate void MqttReceivedMsgHandler(MqttApplicationMessage e);

    public interface IMqttMsgService
    {
        void Init(string serverIp, int port, string clientId, int verNo);
        Task<bool> Connect(MqttReceivedMsgHandler receiveMsgHandler);
        void SubscribeTopics(string topic, int qos = 0);
        void UnscribeTopics(string topic);
        bool IsConnect();
        bool SendMessage(string topic, string content, int qos = 0, bool isRetain = false);
        Task Disconnect();
    }

    public class MqttMsgService: IMqttMsgService
    {
        private IManagedMqttClient mqttClient;
        private ManagedMqttClientOptions managedOptions;
        private MqttReceivedMsgHandler receiveHandler;
        private AutoResetEvent _connectEvents;
        public MqttMsgService()
        {
            var mqttFactory = new MqttFactory();
            mqttClient= mqttFactory.CreateManagedMqttClient();
            _connectEvents = new AutoResetEvent(false);
        }

        public void Init(string serverIp, int port, string clientId,int verNo)
        {
            var ver = MQTTnet.Formatter.MqttProtocolVersion.V500;
            if(verNo==0)
            {
                ver = MQTTnet.Formatter.MqttProtocolVersion.V311;
            }
            var mqttOption = new MqttClientOptionsBuilder()
                   .WithTcpServer(serverIp, port)
                 .WithClientId(clientId)
                 .WithProtocolVersion(ver)
                 .WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
                 .WithCleanSession()
                 .WithTimeout(TimeSpan.FromSeconds(10))
                 .WithKeepAlivePeriod(TimeSpan.FromSeconds(30))
                 .Build();

            managedOptions = new ManagedMqttClientOptionsBuilder()
                .WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
                .WithClientOptions(mqttOption)
                .Build();
            
       
        }

        public async Task<bool> Connect(MqttReceivedMsgHandler receiveMsgHandler)
        {

            bool isSuccess = false;
            try
            {
                if (managedOptions == null) {
                    return isSuccess;
                }
                _connectEvents.Reset();
                receiveHandler = receiveMsgHandler;
                mqttClient.ConnectedAsync -= Connected_Event;
                mqttClient.ConnectedAsync += Connected_Event;
                mqttClient.ApplicationMessageReceivedAsync -= Receive_Event;
                mqttClient.ApplicationMessageReceivedAsync += Receive_Event;
                var connectTask = mqttClient.StartAsync(managedOptions);
                isSuccess = _connectEvents.WaitOne(TimeSpan.FromSeconds(10));
                await connectTask;
            }
            catch (Exception ex)
            {
                isSuccess = false;
            }
            return isSuccess;
        }

        public async void SubscribeTopics(string topic, int qos = 0)
        {
            if (mqttClient.IsConnected)
            {
                await mqttClient.SubscribeAsync(topic, (MqttQualityOfServiceLevel)qos);
            }
        }

        public void UnscribeTopics(string topic)
        {
            if (mqttClient.IsConnected)
            {
                mqttClient.UnsubscribeAsync(topic);
            }
        }

        public bool IsConnect()
        {
            return mqttClient.IsConnected;
        }

        public bool SendMessage(string topic, string content, int qos = 0, bool isRetain = false)
        {
            bool isSuccess = false;
            if (mqttClient.IsConnected)
            {
                var msgBuilder = new MqttApplicationMessageBuilder()
                                .WithTopic(topic)
                                .WithPayload(content)
                               //5.0 消息过期时间
                               .WithMessageExpiryInterval((uint)60)
                               .WithRetainFlag(isRetain)
                               .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)qos);
                var msg = msgBuilder.Build();
                mqttClient.EnqueueAsync(msg);
                isSuccess = true;
            }
            return isSuccess;
        }

        public async Task Disconnect()
        {
            await mqttClient.StopAsync();
            mqttClient.ConnectedAsync -= Connected_Event;
            mqttClient.ApplicationMessageReceivedAsync -= Receive_Event;
        }


        #region
        private Task Receive_Event(MqttApplicationMessageReceivedEventArgs arg)
        {
            if (receiveHandler != null)
            {
                return Task.Run(() => receiveHandler.Invoke(arg.ApplicationMessage));
            }
            return Task.CompletedTask;
        }

        private Task Connected_Event(MqttClientConnectedEventArgs arg)
        {
            _connectEvents.Set();
            return Task.CompletedTask;
        }

        #endregion

    }
}
